package utils

import (
	"ahutoj/web/io/response"
	"compress/gzip"
	"crypto/tls"
	"encoding/json"
	"io"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"

	"golang.org/x/net/http2"

	"github.com/gin-gonic/gin"
)

type HttpMethodType string
type UserStatus int64

const (
	POST   HttpMethodType = "POST"
	GET    HttpMethodType = "GET"
	DELETE HttpMethodType = "DELETE"
	PUT    HttpMethodType = "PUT"
)

func WithoutRedirect(client *http.Client){
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		return http.ErrUseLastResponse
	}
}
func WithProxy(client *http.Client, proxyUrl string){
	if ! GetConfInstance().ProxyConfig.UseProxy{
		return
	}
	Url, _ := url.Parse(proxyUrl)
	dialer := &net.Dialer{
		// 限制创建一个TCP连接使用的时间（如果需要一个新的链接）
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
	}
	netTransport := http.Transport{
		DialContext: dialer.DialContext,
		Proxy: http.ProxyURL(Url),
		DisableKeepAlives: true,
		MaxConnsPerHost:   20,
		// 是长连接在关闭之前，连接池对所有host的最大链接数量
		MaxIdleConns: 20,
		// 连接池对每个host的最大链接数量(MaxIdleConnsPerHost <= MaxIdleConns,如果客户端只需要访问一个host，那么最好将MaxIdleConnsPerHost与MaxIdleConns设置为相同，这样逻辑更加清晰)
		MaxIdleConnsPerHost: 20,
		// 连接最大空闲时间，超过这个时间就会被关闭
		IdleConnTimeout:       20 * time.Second,
		ResponseHeaderTimeout: 30 * time.Second,
		TLSClientConfig:       &tls.Config{InsecureSkipVerify: true},
	}
	_ = http2.ConfigureTransport(&netTransport)
	client.Transport = &netTransport
}
func ConfigureClient(client *http.Client,configs ...func(*http.Client)) {
	for _, config := range configs {
		config(client)
	}
}
/*useRedirect 是否使用重定向，不是的话跳过重定向，是就不管*/
func DoRequest(method HttpMethodType, url string, headers map[string]string, cookies map[string]string, body *string,configs ...func(*http.Client)) (*http.Response, error) {
	logger := GetLogInstance()
	client := &http.Client{}
	ConfigureClient(client,configs...)
	var data io.Reader = nil
	contntLength := 0
	if body != nil {
		data = strings.NewReader(*body)
		contntLength = len(*body)
	}
	req, err := http.NewRequest(string(method), url, data)
	if err != nil {
		logger.Errorf("call NewRequest failed,method=%v, url=%v, data=%v, err=%v", method, url, body, err.Error())
		return nil, err
	}
	req.ContentLength = int64(contntLength)
	if cookies != nil {
		req.Header.Set("Cookie", MapToStrings(cookies, ";"))
	}
	for key, value := range headers {
		req.Header.Set(key, value)
	}
	resp, err := client.Do(req)
	if err != nil {
		logger.Errorf("call Do failed,req=%+v ,err=%s", Sdump(req), err.Error())
		return nil, err
	}
	return resp, nil
}

func MapToStrings(data map[string]string, sep string) string {
	if data == nil {
		return ""
	}
	strs := make([]string, 0)
	for key, value := range data {
		strs = append(strs, key+"="+value)
	}
	return strings.Join(strs, sep)
}

func MapToFormStrings(data map[string]string, sep string) string {
	if data == nil {
		return ""
	}
	strs := make([]string, 0)
	for key, value := range data {
		key = url.QueryEscape(key)
		value = url.QueryEscape(value)
		strs = append(strs, key+"="+value)
	}
	return strings.Join(strs, sep)
}

func ParseRespToReader(resp *http.Response) io.ReadCloser {
	var reader io.ReadCloser
	if resp.Header.Get("Content-Encoding") == "gzip" {
		reader, _ = gzip.NewReader(resp.Body)
	} else {
		reader = resp.Body
	}
	return reader
}

func ParseRespToByte(resp *http.Response) ([]byte, error) {
	var reader io.ReadCloser
	if resp.Header.Get("Content-Encoding") == "gzip" {
		reader, _ = gzip.NewReader(resp.Body)
	} else {
		reader = resp.Body
	}
	return io.ReadAll(reader)
}

func Resp4Gin(ctx *gin.Context, resp *http.Response) {
	defer resp.Body.Close()

	ctx.Status(resp.StatusCode)

	for key, values := range resp.Header {
		for _, value := range values {
			ctx.Header(key, value)
		}
	}

	// 复制响应体
	_, err := io.Copy(ctx.Writer, resp.Body)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
}

func Resp4Map(ctx *gin.Context, resp *http.Response,response response.Response)(map[string]interface{}) {
	logger := GetLogInstance()
	defer resp.Body.Close()
	var data map[string]interface{}
	r,err:=ParseRespToByte(resp)
	if err!=nil {
		logger.Errorf("call ParseRespToByte failed,err=%v", err.Error())
		return nil
	}
	err = json.Unmarshal(r, &data)
	if err != nil {
		logger.Errorf("call Unmarshal failed,data=%v, err=%v", string(r), err.Error())
		return nil
	}

	data["Code"] = response.StatusCode
	data["Msg"] = response.StatusMsg
	return data
}

func DealStrings(str string) string {
	ret := ""
	for _, ch := range str {
		if ch == '\n' || ch == '\t' {
			continue
		}
		ret += string(ch)
	}
	return strings.Trim(ret, " ")
}
